﻿using System;
using System.IO;
using System.Xml.Linq;
namespace DBAccessTestFramework
{
    public class ScriptElement
    {
        public const string ElementName = "script";
        public const string AttributeName = "name";
        public const string AttributeSource = "source";

        public ScriptElement()
        {
            this.Source = ScriptType.Command;
        }

        public string Name { get; set; }

        public ScriptType Source { get; set; }

        public string Value { get; set; }

        public static ScriptElement Load(XElement xml, string filename)
        {
            if (xml.Name != ElementName)
            {
                string message = string.Format("Invalid element name: '{0}'. Expected: '{1}'.", xml.Name, ElementName);
                throw new InvalidOperationException(message);
            }

            var result = new ScriptElement();
            result.DecodeAttributes(xml);
            result.DecodeValue(xml, filename);
            FileDefinitionHelper.ValidateAttribute(result.Name, ElementName, AttributeName);

            return result;
        }

        private void DecodeValue(XElement xml, string filename)
        {
            switch (this.Source)
            {
                case ScriptType.Command:
                    this.Value = xml.Value;
                    break;

                case ScriptType.File:
                    if (File.Exists(xml.Value))
                    {
                        this.Value = xml.Value;
                        return;
                    }

                    string path = Path.GetDirectoryName(filename);
                    path = Path.Combine(path, xml.Value);
                    if (!File.Exists(path))
                    {
                        throw new FileNotFoundException(path);
                    }

                    this.Value = File.ReadAllText(path);
                    break;

                default:
                    throw new InvalidOperationException("Invalid Source");
            }
        }

        private void DecodeAttributes(XElement xml)
        {
            string message;
            foreach (var attribute in xml.Attributes())
            {
                switch (attribute.Name.LocalName)
                {
                    case AttributeName:
                        this.Name = attribute.Value;
                        break;
                    case AttributeSource:
                        try
                        {
                            this.Source = (ScriptType)Enum.Parse(typeof(ScriptType), attribute.Value);
                        }
                        catch (Exception ex)
                        {
                            message = string.Format("Element: '{0}'. Invalid attribute '{1}'.", ElementName, attribute.Name);
                            throw new InvalidOperationException(message, ex);
                        }

                        break;
                    default:
                        message = string.Format("Element: '{0}'. Invalid attribute '{1}'.", ElementName, attribute.Name);
                        throw new InvalidOperationException(message);
                }
            }
        }

        public enum ScriptType
        {
            File,
            Command
        }
    }
}
